import {
  ConstraintType,
  CSLine,
  EventsRes,
  ICurve,
  ISketcherData,
  SceneGraph,
} from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import { calculatePoint } from '@app-cad/common/utils';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '@app-cad/environments/nextcad/events/SketchEventCenter';
import { wsApi } from '@app-cad/server';
import { Vector2tuple, Vector3 } from 'three-legacy';
import CmdBase, { PickType } from '../../CmdBase';
import { dimension } from '../dimension/Dimension';
import { MouseState, State } from './types';
import { SketchLineCreateTask } from './LineCreatedTask';
import { sketchStore } from '@app-base/common/utils/sketchTools/useSketchStore';
import { loadEmit } from '@app-base/common/events/CoreEvent';
import { SnapResult } from '@app-base/common/utils/sketchTools/SnapManager';

export default class CmdInteractor extends CmdBase {
  pickLineObj: CSLine;
  private startPoint: Vector3; // 绘制起点
  private startSnap: SnapResult;
  private endPoint: Vector3; // 绘制终点
  private endSnap: SnapResult;
  lastEndPoint: string; // 上一个点
  // 点在线上
  private pointOnline: ICurve;
  private task: SketchLineCreateTask;
  // 起点到终点的距离
  private points: Vector3[] = [];
  private currentState: MouseState = State.NONE;

  // 尺寸约束
  constructor(
    private mode: '2point' | 'mid-point',
    public onFinishDraw?: (curve: ICurve) => void,
    public needSetEventCenterState = true,
  ) {
    super();
    this.task = new SketchLineCreateTask();
    this.registerEvents();
  }

  reset() {
    this.currentState = State.NONE;
    this.assistPoints = [];
    this.points = [];
    this.startPoint = null;
    this.startSnap = null;
    this.endPoint = null;
    this.endSnap = null;
    this.pointOnline = null;
    this.removeTempPoint();
  }

  enterKeyDown = () => {
    if (this.currentState === State.DRAW) {
      const flag = dimension().determineDim();
      if (flag) {
        dimension().determineDim();
        this.setLineLength();
        this.preview();
      }
    }
  };

  registerEvents() {
    if (this.needSetEventCenterState) {
      sketchEventCenter().setState('CmdLine');
    }

    sketchEventCenter()
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .on(SKETCH_CENTEREVENTS.DBCLICK, this.onDbClick)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy.bind(this));
  }

  unregisterEvents() {
    if (this.needSetEventCenterState) {
      sketchEventCenter().setDefault();
    }

    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .off(SKETCH_CENTEREVENTS.DBCLICK, this.onDbClick)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp);
    dimension()?.reset();
  }

  onDbClick = () => {
    // 鼠标右键，完成
    this.reset();
    this.releaseObjects();
  };

  releaseObjects() {
    dimension()?.destroy();
    this.clearLine();
    this.assisGroup.clear();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  }

  onMouseMove = (e: EventsRes) => {
    // 设置点位根据鼠标位置
    this.setMouseWV(e, dimension()?.getDimInfo() ? false : true); // 设置鼠标位置
    if (this.currentState === State.DRAW) {
      this.endPoint = this.mouseWV;
      this.endSnap = this.currentSnapInfo;
      this.isVorH = this.isSamePoint(this.startPoint, this.endPoint);
      if (this.isVorH) {
        this.creatUpdateLabel(this.endPoint, this.isVorH);
      } else {
        this.showLabel(false);
      }
      this.setLineLength();
      if (this.points.length == 1) {
        this.points.push(this.endPoint);
      } else {
        this.points[this.points.length - 1] = this.endPoint;
      }
      this.preview();
    }
  };
  setLineLength() {
    if (dimension().dimType === 'create') {
      const vec = new Vector3()
        .subVectors(this.endPoint, this.startPoint)
        .normalize();
      this.endPoint = calculatePoint(
        vec,
        dimension().getDimInfo()?.value *
          (this.mode === 'mid-point' ? 1 / 2 : 1),
        this.startPoint,
      );
      this.endSnap = null;
    }
    // 添加辅助点，用来做定点捕捉
    this.createAssistPoint(this.endPoint, true);
  }

  nextLineReady() {
    this.previewLines.line = null;
    this.removeAssistPoint();
    this.createAssistPoint(this.endPoint, null, null, true);
    this.startPoint = this.endPoint;
    this.startSnap = null;
    this.endSnap = null;
    this.lastEndPoint = null;
    this.isVorH = null;
  }

  setStartPoint(pointId: string) {
    this.lastEndPoint = pointId;
    this.currentState = State.DRAW;
    const pointData = sketchStore
      .getState()
      .curves.find((c) => c.id === pointId);

    this.startPoint = new Vector3(...pointData.vertices[0]);
    this.startSnap = null;
  }

  onMouseDown = (e: EventsRes) => {
    if (e.button.onLeft) {
      // 鼠标左键，进行绘制
      if (this.currentState === State.NONE) {
        this.task.clear();
        this.startPoint = this.mouseWV;
        this.startSnap = this.currentSnapInfo;
        this.previewLines.line = null;
        if (this.pickType === PickType.Point) {
          this.lastEndPoint = this.pickSnapInfo.id;
        } else {
          this.lastEndPoint = null;
        }
        if (
          this.pickType === PickType.Line &&
          this.pickSnapInfo?.type !== 'Bspline'
        ) {
          this.pointOnline = this.pickSnapInfo;
        }
        this.points.push(this.startPoint);
        // （编辑线） 添加辅助点
        this.createAssistPoint(this.startPoint, null, null, true);
        this.currentState = State.DRAW;
      } else if (
        this.currentState === State.DRAW &&
        this.endPoint &&
        this.startPoint
      ) {
        this.finishDraw();
        this.nextLineReady();
      }
    } else if (e.button.onRight && !this.closeRightClick) {
      // 鼠标右键，取消绘制
      this.reset();
      this.releaseObjects();
    }
  };

  preview() {
    if (this.currentState === State.DRAW && this.endPoint && this.startPoint) {
      // 绘制
      const point1 =
        this.mode === '2point'
          ? this.startPoint
          : new Vector3().subVectors(
              this.startPoint.clone().multiplyScalar(2),
              this.endPoint,
            );
      const point2 = this.endPoint;

      if (point1.distanceToSquared(point2) < 1e-3) {
        return;
      }
      dimension().dimLine([point1, point2]);
      this.createUpdateLine([point1, point2]);
      ctx2.viewer.requestRender();
    }
  }

  // 完成绘制
  async finishDraw() {
    if (this.startPoint.equals(this.endPoint)) {
      return;
    } // 防止点重复
    if (this.startPoint && this.endPoint) {
      const point1: Vector2tuple = [this.startPoint.x, this.startPoint.y];
      // 做重合约束
      let point2: string | Vector2tuple = [this.endPoint.x, this.endPoint.y];
      if (this.pickType === PickType.Point && this.pickSnapInfo) {
        point2 = this.pickSnapInfo.id;
      }
      this.task.add((resId) =>
        this.createLine(
          this.lastEndPoint || resId,
          point1,
          point2,
          this.currentState,
          this.isVorH,
        ),
      );
    }
  }

  async createLine(
    lastEndPoint: string,
    point1: Vector2tuple,
    point2: string | Vector2tuple,
    currentState: MouseState,
    isVorH: 'V' | 'H',
  ) {
    const p = lastEndPoint || point1;
    const param = this.getParams([p, point2], isVorH);
    if (this.mode === 'mid-point') {
      this.currentState = State.NONE;
      this.lastEndPoint = null;
    }
    try {
      loadEmit(true);
      const res = await wsApi.createSketchLine(this.sketchId, param);

      const addData = (await this.render(res, !!param.annotations[0]))
        .addData as ISketcherData;
      if (addData) {
        const curveInfo = addData?.curves?.find((item) => item.type === 'Line');
        const pointIds = curveInfo?.relative;
        if (pointIds?.length <= 2) {
          return;
        }
        if (currentState === State.DRAW) {
          {
            this.lastEndPoint = pointIds[1];
            this.onFinishDraw?.(curveInfo);
          }
        }
      }
      if (this.mode === 'mid-point') {
        this.releaseObjects();
      }
      dimension().destroy();
      return this.lastEndPoint;
    } finally {
      loadEmit(false);
    }
  }

  getParams([point1, point2]: (string | Vector2tuple)[], isVorH: 'V' | 'H') {
    return {
      mode: this.mode,
      point1,
      point2,
      curveStyle: this.lineType,
      constraints: this.getConstraints(isVorH),
      annotations: [dimension().addDimension([], 2)],
    };
  }

  getConstraints(isVorH?: 'V' | 'H') {
    const constraints = [];

    constraints.push(...this.getPointConstraintsFromSnapResult(this.startSnap));
    constraints.push(...this.getPointConstraintsFromSnapResult(this.endSnap));
    if (isVorH) {
      constraints.push({
        curve: '',
        target: '',
        type:
          this.isVorH === 'V'
            ? ConstraintType.Vertical
            : ConstraintType.Horizontal,
      });
    }
    return constraints;
  }
}
